<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
require_once "JaroWinkler.php";
/**
 * 
 * Genel metin araçları. String benzerliği, Q klavye mesafesi gibi fonksiyonları barındırır.
 *
 * @author acer
 * Tested in 25.12.2011 17:04
 */
class MetinAraclari {
    //put your code here
    
    private static $jaroWinkler;
    
    /**
     *
     * @return JaroWinkler 
     */
    private static function getJaroWinkler() {
        if(is_null(self::$jaroWinkler)) {
            self::$jaroWinkler = new JaroWinkler();
        }
        return self::$jaroWinkler;
    }
    
    /**
     * Değiştirilmiş Levenshtein algoritması. Transpozisyonları da 1 düzeltme mesafesi olarak hesaplar.
     * @param string $s: kaynak stringi
     * @param string $t: hedef stringi
     * @param int $limit: sınır değeri
     * @return int: iki kelime arasındaki mesafe, tamsayı cinsinden. Küçük rakamlar daha büyük benzerlik gösterir.
     */
    private static function duzeltmeMesafesi($s, $t, $limit = null) {
        $n = strlen($s);
        $m = strlen($t);
        if(is_null($limit)) {
            $limit = max(array($n, $m));
        }
        $d = array();
        for($i = 0; $i <= $n; $i++) {
            $d[$i] = array();
            for($j = 0; $j <= $m; $j++) {
                $d[$i][$j] = 0;
            }
        }
        $cost = 0;
        if($n == 0) {
            return $m;
        }
        if($m == 0) {
            return $n;
        }
        for($i = 0; $i <= $n; $d[$i][0] = $i++);
        for($j = 0; $j <= $n; $d[0][$j] = $j++);
        for($i = 1; $i <= $n; $i++) {
            for($j = 1; $j <= $m; $j++) {
                $cost = $t[$j - 1] == $s[$i - 1] ? 0 : 1;
                $d[$i][$j] = min(array(
                    min(array($d[$i - 1][$j] + 1, $d[$i][$j - 1])),
                    $d[$i - 1][$j - 1] + $cost
                ));
                if($i > 1 && $j > 1) {
                    $trans = $d[$i - 2][$j - 2] + 1;
                    if($s[$i - 2] != $t[$j - 1]) {
                        $trans++;
                    }
                    if($s[$i - 1] != $t[$j - 2]) {
                        $trans++;
                    }
                    if($d[$i][$j] > $trans) {
                        $d[$i][$j] = $trans;
                    }
                }
            }
        }
        return $d[$n][$m] > $limit ?  $limit + 1 : $d[$n][$m];
    }
    
    /**
     *
     * @param string $source
     * @param string $target
     * @param int $dist
     * @return boolean 
     */
    public static function duzeltmeMesafesiIcinde($source, $target, $dist) {
        return (self::duzeltmeMesafesi($source, $target, $dist) <= $dist);
    }
    
    /**
     * Verilen s1 stringinin verilen distance düzeltme mesafesi çerçevesinde s2 stringinin alt stringi olup olmadığını döndürür.
     * Örneğin:
     * parcasiDuzeltmeMesafesiIcinde("elma", "ekmalar", 1) -> true
     * parcasiDuzeltmeMesafesiIcinde("elma", "emalar", 1) -> true
     * parcasiDuzeltmeMesafesiIcinde("elma", "eksalar", 1) -> false
     * 
     * @param string $s1
     * @param string $s2: s1'i düzeltme mesafesi içinde kapsayıp kapsamadığı araştırılan string
     * @param int $distance: düzeltme mesafesi
     * @return boolean: eğer istenilen mesafede ise true. 
     */
    public static function parcasiDuzeltmeMesafesiIcinde($s1, $s2, $distance) {
        if(strlen($s2) < (strlen($s2) - $distance)) {
            return false;
        }
        if(strlen($s2) >= strlen($s1)) {
            $test = substr($s2, 0, strlen($s1));
            if(self::duzeltmeMesafesiIcinde($s1, $test, $distance)) {
                return true;
            }
            $test = substr($s2, 0, strlen($s1) - 1);
            if(self::duzeltmeMesafesiIcinde($s1, $test, $distance)) {
                return true;
            }
            if(strlen($s2) >= strlen($s1) + 1) {
                $test = substr($s2, 0, strlen($s1) + 1);
                if(self::duzeltmeMesafesiIcinde($s1, $test, $distance)) {
                    return true;
                }
            }
        } else {
            if(self::duzeltmeMesafesiIcinde($s1, $s2, $distance)) {
                return true;
            }
        }
        return false;
    }
    
    public static function sozcukBenzerlikOrani($s1, $s2) {
        $jw = self::getJaroWinkler();
        return $jw->benzerlikOrani($s1, $s2);
    }
    
    public static function sozcukBenzerlikTesti($s1, $s2, $enazBenzerlik) {
        $jw = self::getJaroWinkler();
        return ($jw->benzerlikOrani($s1, $s2) >= $enazBenzerlik);
    }
}